package bma.common.langutil.ai.common;

import java.util.concurrent.atomic.AtomicBoolean;

import bma.common.langutil.ai.stack.AIStack;
import bma.common.langutil.ai.vm.AIContext;
import bma.common.langutil.ai.vm.AIContextNow;
import bma.common.langutil.concurrent.ProcessTimerTaskAbstract;
import bma.common.langutil.core.ObjectUtil;

public abstract class AITimeoutTask<TYPE> extends ProcessTimerTaskAbstract
		implements AIStack<TYPE> {

	private final AtomicBoolean called = new AtomicBoolean();
	protected final AIContext context;
	protected final AIStack<TYPE> stack;

	public AITimeoutTask(AIStack<TYPE> stack, AIContext ctx, long timeout) {
		super(System.currentTimeMillis() + timeout, ctx == null ? false : true);
		this.stack = stack;
		this.context = ctx;
	}

	@Override
	public void run() {
		if (called.getAndSet(true)) {
			return;
		}
		stackTimeout(AIContextNow.check(this.context), this.stack);
	}

	protected abstract void stackTimeout(AIContext ctx, AIStack<TYPE> stack);

	@Override
	public boolean success(TYPE result) {
		if (called.getAndSet(true)) {
			return true;
		}
		return this.stack.success(result);
	}

	@Override
	public boolean failure(Throwable t) {
		if (called.getAndSet(true)) {
			return true;
		}
		return this.stack.failure(t);
	}

	@Override
	public AIStack<?> getParent() {
		return this.stack.getParent();
	}

	@Override
	public boolean equals(Object obj) {
		if (super.equals(obj))
			return true;
		if (obj instanceof AIStack) {
			AIStack st = (AIStack) obj;
			return ObjectUtil.equals(st, this.stack);
		}
		return false;
	}
}
